package calculator.handler;

import calculator.operator.Operator;
import calculator.operator.sequential.SequentialOperation;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

@SuppressWarnings("all")
public class ExpressionHandler {


    public List<Object> toSuffix(String expr){

        if (isNotRational(expr))
            throw new RuntimeException("非法的表达式");

        List result = new ArrayList();
        Stack<Operator> operatorStack = new Stack<>();
        OperatorHandler operatorHandler = new OperatorHandler();

        int index = 0;
        int max = expr.length() - 1;


        while (index <= max){

            char current = expr.charAt(index);
            String num = "";

            if (isNum(current)){

                num += current;
                char next;

                while (++index <= max && isNumOrPoint( (next = expr.charAt(index)) ) ){
                    num += next;
                }

                if (isPi(num.charAt(0))){
                    result.add(Math.PI);
                    continue;
                }

                result.add(Double.parseDouble(num));

            }else {

               Operator operator = operatorHandler.getOperator(current);

               if (isSeqOperator(operator)){
                   handleSeqOperator(result, (SequentialOperation)operator, operatorStack);
               }else {
                   handleCalOperator(result, operator, operatorStack);
               }
               index++;

            }

        }

        while (!operatorStack.isEmpty()){
            result.add(operatorStack.pop());
        }

        return result;

    }

    private boolean isNotRational(String expr){
        if (null == expr)
            return true;

        if (expr.length() <= 0)
            return true;

        return false;
    }

    private boolean isNum(char current){
        return isPi(current) || current >= 48 && current <= 57;
    }

    private boolean isPi(char current) {return current == 'π';}

    private boolean isNumOrPoint(char current){return isNum(current) || current == 46;}

    private boolean isSeqOperator(Operator operator){
        return operator instanceof SequentialOperation;
    }

    private void handleSeqOperator(List result, SequentialOperation operator, Stack<Operator> operatorStack){

        if (operator.isLeft()){
            operatorStack.push(operator);
        }else {
            while (!operatorStack.isEmpty()){
                Operator top = operatorStack.pop();
                if (operator.isOtherHalf(top)){
                    break;
                }else {
                    result.add(top);
                }
            }

        }
    }

    private void handleCalOperator(List result, Operator operator, Stack<Operator> operatorStack){
        while (true){
            if (operatorStack.isEmpty() || operatorStack.peek() instanceof SequentialOperation){
                operatorStack.push(operator);
                break;
            }else if (operator.getPriority() > operatorStack.peek().getPriority()){
                operatorStack.push(operator);
                break;
            }else {
                result.add(operatorStack.pop());
            }
        }
    }



}
